package com.shanzmoo.merchant.server.api.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alipay.easysdk.base.oauth.models.AlipaySystemOauthTokenResponse;
import com.shanzmoo.base.constant.e.LoginUserType;
import com.shanzmoo.base.util.RedisUtil;
import com.shanzmoo.base.util.SpringUtil;
import com.shanzmoo.core.domain.AllAlipayClient;
import com.shanzmoo.db.module.member.entity.MemberInfoEntity;
import com.shanzmoo.db.module.member.entity.MemberMerchantEntity;
import com.shanzmoo.db.module.member.entity.MemberMerchantTmpEntity;
import com.shanzmoo.db.module.member.service.IMemberInfoService;
import com.shanzmoo.db.module.member.service.IMemberMerchantService;
import com.shanzmoo.db.module.member.service.IMemberMerchantTmpService;
import com.shanzmoo.db.module.pay.entity.STerminalInfoEntity;
import com.shanzmoo.db.module.pay.service.ISTerminalInfoService;
import com.shanzmoo.merchant.server.api.domain.AuthUser;
import com.shanzmoo.merchant.server.api.domain.bo.LoginRegBo;
import com.shanzmoo.merchant.server.api.domain.vo.AuthUserVo;
import com.shanzmoo.merchant.server.api.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import me.chanjar.weixin.mp.api.WxMpService;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 用户管理
 * @author fs
 */
@Component
@RequiredArgsConstructor
public class MemberInfoManage {
    private final IMemberInfoService iMemberInfoService;
    private final IMemberMerchantTmpService iMemberMerchantTmpService;
    private final IMemberMerchantService iMemberMerchantService;
    private final WxMpService wxMpService;
    private final ISTerminalInfoService isTerminalInfoService;
    private final AllAlipayClient allAlipayClient;
    @Transactional(rollbackFor = Exception.class)
    public String getUserNameByLogin(Integer type, String mobile, String code, String wxId, String zfbId){
        //分为0和 2
        LoginUserType userType = LoginUserType.codeof(type);
        if(userType == null || userType == LoginUserType.SH_TEMP){
            //登录类型必须是0代表平台会员登录2代表商户会员登录,因此类型不存在或者为1的跳过
            return null;
        }
        String username = null;
        if(userType == LoginUserType.PT_FORMAL){
            //需要同时处理正式平台会员
            if(StrUtil.isNotBlank(wxId)){
                //微信登录
                username = StrUtil.format("{}___{}",LoginUserType.PT_FORMAL.toString(),wxId);
            }else if(StrUtil.isNotBlank(zfbId)){
                //支付宝登录
                username = StrUtil.format("{}___{}",LoginUserType.PT_FORMAL.toString(),zfbId);
            }
        }else if(userType == LoginUserType.SH_HUIYUAN || userType == LoginUserType.SH_TEMP){
            //需要处理商户会员和临时会员
            if(StrUtil.isNotBlank(wxId)){
                //微信登录
                username = StrUtil.format("{}___{}",userType.toString(),wxId);
            }else if(StrUtil.isNotBlank(zfbId)){
                //支付宝登录
                username = StrUtil.format("{}___{}",userType.toString(),zfbId);
            }else if(StrUtil.isNotBlank(mobile)){
                //手机号登录
                String phoneCode = RedisUtil.get("merchant-server-api:login:phone-code:"+mobile);
                //Assert.isTrue(StrUtil.equals(phoneCode,code),"手机验证码错误");
                username = StrUtil.format("{}___{}",userType.toString(),mobile);
            }
        }
        return username;
    }
    public Object findUserByUserName(String username){
        String[] us = username.split("___");
        LoginUserType type = LoginUserType.valueOf(us[0]);
        String loginUserName = us[1];
        if(LoginUserType.PT_FORMAL == type){
            //平台正式用户
            MemberInfoEntity user = iMemberInfoService
                    .lambdaQuery()
                    .and(tmp -> tmp.eq(MemberInfoEntity::getWxOpenId,loginUserName)
                            .or()
                            .eq(MemberInfoEntity::getZfbOpenId,loginUserName))
                    .one();
            if(user == null){
                throw new UsernameNotFoundException("用户不存在");
            }
            return user;
        }else if(LoginUserType.SH_HUIYUAN == type || LoginUserType.SH_TEMP == type){
            //商家会员用户 和  临时商家会员用户
            MemberMerchantEntity user = iMemberMerchantService
                    .lambdaQuery()
                    .and(tmp -> tmp.eq(MemberMerchantEntity::getOpenId,loginUserName)
                            .or()
                            .eq(MemberMerchantEntity::getBuyerId,loginUserName)
                            .or()
                            .eq(MemberMerchantEntity::getMobile,loginUserName)
                    )
                    .one();
            if(user != null){
                return user;
            }
            MemberMerchantTmpEntity user2 = iMemberMerchantTmpService
                    .lambdaQuery()
                    .and(tmp -> tmp.eq(MemberMerchantTmpEntity::getOpenId,loginUserName)
                            .or()
                            .eq(MemberMerchantTmpEntity::getBuyerId,loginUserName))
                    .one();
            if(user2 == null){
                throw new UsernameNotFoundException("用户不存在");
            }
            return user2;
        }else{
            return null;
        }
    }
    public UserDetails findByUserName(String username){
        Object user = findUserByUserName(username);
        if(user == null){
            throw new UsernameNotFoundException("用户不存在");
        }
        return AuthUser.createObj(user);
    }
    public AuthUserVo getAuthUserLogin(Integer type, String mobile, String code, String wxId, String zfbId) {
        String username = getUserNameByLogin(type,mobile,code,wxId,zfbId);
        Authentication authentication = SpringUtil.getBean(AuthenticationManager.class).authenticate(
                new UsernamePasswordAuthenticationToken(username, "1"));
        SecurityContextHolder.getContext().setAuthentication(authentication);
        AuthUser authUser = BeanUtil.toBean(authentication.getPrincipal(),AuthUser.class);
        String jwt = SpringUtil.getBean(JwtManager.class).createJWT(false, authUser.getUserId(), authUser.getUsername());
        Object user = findUserByUserName(username);
        AuthUserVo userVo = new AuthUserVo();
        userVo.setToken(jwt);
        if(user instanceof MemberInfoEntity){
            MemberInfoEntity info =  (MemberInfoEntity)user;
            userVo.setUserId(info.getId());
            userVo.setMobile(info.getMobile());
            userVo.setUserType(LoginUserType.PT_FORMAL);
        }else if(user instanceof MemberMerchantTmpEntity){
            MemberMerchantTmpEntity info =  (MemberMerchantTmpEntity)user;
            userVo.setUserId(info.getId());
            userVo.setUserType(LoginUserType.SH_TEMP);
        }else if(user instanceof MemberMerchantEntity){
            MemberMerchantEntity info =  (MemberMerchantEntity)user;
            userVo.setUserId(info.getId());
            userVo.setMobile(info.getMobile());
            userVo.setUserType(LoginUserType.SH_HUIYUAN);
        }else{
            return null;
        }
        return userVo;
    }
    @Transactional(rollbackFor = Exception.class)
    public AuthUserVo reg(LoginRegBo regBo) {
        Assert.notNull(regBo.getType(),"类型不可为空");
        Assert.isTrue(CollUtil.newArrayList(0,1,2).contains(regBo.getType()),"此类型用户不存在");
        STerminalInfoEntity terminalInfo = null;
        switch (regBo.getType()){
            case 0:
                Assert.isTrue(false,"平台用户注册暂未处理");
                break;
            case 1:
                terminalInfo = isTerminalInfoService
                        .lambdaQuery()
                        .eq(STerminalInfoEntity::getTerminalId,regBo.getTerminalNo())
                        .one();
                Assert.notNull(terminalInfo,"当前终端二维码存在问题");
                if(StrUtil.isNotBlank(regBo.getWxCode())){
                    //微信用户登录创建
                    String openId = getWxOpenId(regBo.getWxCode());
                    Assert.notBlank(openId,"未获取到用户openId");
                    MemberMerchantTmpEntity tmpEntity = iMemberMerchantTmpService.lambdaQuery().eq(MemberMerchantTmpEntity::getOpenId,openId).one();
                    if(tmpEntity == null){
                        tmpEntity = new MemberMerchantTmpEntity();
                        tmpEntity.setOpenId(openId);
                        tmpEntity.setMerchantCode(terminalInfo.getMerchantNo());
                        iMemberMerchantTmpService.save(tmpEntity);
                    }
                    return getAuthUserLogin(2,null,null,openId,null);
                }else if(StrUtil.isNotBlank(regBo.getZfbCode())){
                    //支付宝用户创建
                    String zfbUserId = getAlipayUserId(regBo.getZfbCode());
                    Assert.notBlank(zfbUserId,"未获取到用户zfbUserId");
                    MemberMerchantTmpEntity tmpEntity = iMemberMerchantTmpService.lambdaQuery().eq(MemberMerchantTmpEntity::getBuyerId,zfbUserId).one();
                    if(tmpEntity == null){
                        tmpEntity = new MemberMerchantTmpEntity();
                        tmpEntity.setBuyerId(zfbUserId);
                        tmpEntity.setMerchantCode(terminalInfo.getMerchantNo());
                        iMemberMerchantTmpService.save(tmpEntity);
                    }
                    return getAuthUserLogin(2,null,null,null,zfbUserId);
                }else{
                    Assert.isTrue(false,"缺少支付宝code或微信code");
                }
                break;
            case 2:
                terminalInfo = isTerminalInfoService
                        .lambdaQuery()
                        .eq(STerminalInfoEntity::getTerminalId,regBo.getTerminalNo())
                        .one();
                Assert.notNull(terminalInfo,"当前终端二维码存在问题");
                Assert.notBlank(regBo.getMobile(),"手机号不可为空");
                String phoneCode = RedisUtil.get("merchant-server-api:login:phone-code:"+regBo.getMobile());
                //Assert.isTrue(StrUtil.equals(phoneCode,regBo.getPhoneCode()),"手机验证码错误");
                MemberInfoEntity user = iMemberInfoService
                        .lambdaQuery()
                        .eq(MemberInfoEntity::getMobile,regBo.getMobile())
                        .one();
                if(user == null){
                    user = new MemberInfoEntity();
                    user.setMobile(regBo.getMobile());
                    user.setStatus(1);
                    user.setScore(0);
                    user.setNickname(regBo.getMobile());
                }
                AuthUser tokenUser = SecurityUtil.getCurrentUser();
                if(tokenUser != null){
                    if(StrUtil.isNotBlank(tokenUser.getWxOpenId())){
                        user.setWxOpenId(tokenUser.getWxOpenId());
                    }
                    if(StrUtil.isNotBlank(tokenUser.getZfbOpenId())){
                        user.setZfbOpenId(tokenUser.getZfbOpenId());
                    }
                }else if(StrUtil.isNotBlank(regBo.getWxCode()) || StrUtil.isNotBlank(regBo.getZfbCode())){
                    if(StrUtil.isNotBlank(regBo.getWxCode())){
                        String openId = getWxOpenId(regBo.getWxCode());
                        if(StrUtil.isNotBlank(openId)){
                            user.setWxOpenId(openId);
                        }
                    }
                    if(StrUtil.isNotBlank(regBo.getZfbCode())){
                        String zfbUserId = getAlipayUserId(regBo.getZfbCode());
                        if(StrUtil.isNotBlank(zfbUserId)){
                            user.setZfbOpenId(zfbUserId);
                        }
                    }
                }
                Assert.isTrue(iMemberInfoService.saveOrUpdate(user),"平台用户更新失败");
                MemberMerchantEntity entity = iMemberMerchantService.lambdaQuery().eq(MemberMerchantEntity::getMobile,regBo.getMobile()).one();
                if(entity == null){
                    entity = new MemberMerchantEntity();
                    entity.setMemberInfoId(user.getId());
                    entity.setMobile(regBo.getMobile());
                    entity.setMerchantCode(terminalInfo.getMerchantNo());
                    entity.setStatus(1);
                    entity.setBalance(0L);
                    entity.setNewFlag(1);
                    entity.setCardNo(RandomUtil.randomNumbers(8));
                }
                if(StrUtil.isNotBlank(user.getWxOpenId())){
                    entity.setOpenId(user.getWxOpenId());
                    iMemberMerchantTmpService.lambdaUpdate().eq(MemberMerchantTmpEntity::getOpenId,user.getWxOpenId()).remove();
                }
                if(StrUtil.isNotBlank(user.getZfbOpenId())){
                    entity.setBuyerId(user.getZfbOpenId());
                    iMemberMerchantTmpService.lambdaUpdate().eq(MemberMerchantTmpEntity::getBuyerId,user.getZfbOpenId()).remove();
                }
                Assert.isTrue(iMemberMerchantService.saveOrUpdate(entity),"平台用户更新失败");
                String phoneCode2 = RandomUtil.randomNumbers(6);
                RedisUtil.set("merchant-server-api:login:phone-code:"+regBo.getMobile(),phoneCode2);
                return getAuthUserLogin(2,regBo.getMobile(),phoneCode2,null,null);
            default:
                Assert.isTrue(false,"此种注册类型不存在");
                break;
        }
        return null;
    }
    public void logout() {
        try {
            // 从redis中删除jwt信息
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes()).getRequest();
            SpringUtil.getBean(JwtManager.class).invalidateJWT(request);
        } catch (SecurityException e) {

        }
    }

    @SneakyThrows
    public String getWxOpenId(String wxCode) {
        String openId = wxMpService.oauth2getAccessToken(wxCode).getOpenId();
        return openId;
    }

    @SneakyThrows
    public String getAlipayUserId(String zfbCode) {
        AlipaySystemOauthTokenResponse res = allAlipayClient.getUser().getToken(zfbCode);
        return res.getUserId();
    }
}
